const fs = require('fs');
const path = require('path');
const { v4: uuidv4 } = require('uuid');
const multer = require('multer');

class FileTransferHandler {
  constructor(db) {
    this.db = db;
    this.uploadDir = process.env.LANCHAT_UPLOAD_DIR || path.join(__dirname, '../../uploads');

    if (!fs.existsSync(this.uploadDir)) {
      fs.mkdirSync(this.uploadDir, { recursive: true });
    }

    this.setupMulter();
  }

  setupMulter() {
    const storage = multer.diskStorage({
      destination: (req, file, cb) => {
        cb(null, this.uploadDir);
      },
      filename: (req, file, cb) => {
        const uniqueName = `${uuidv4()}-${file.originalname}`;
        cb(null, uniqueName);
      }
    });

    this.upload = multer({
      storage: storage,
      limits: {
        fileSize: 100 * 1024 * 1024 * 1024 // 100GB limit
      }
    });
  }

  handleUpload(req, res) {
    const uploadSingle = this.upload.single('file');

    uploadSingle(req, res, (err) => {
      if (err) {
        console.error('Upload error:', err);
        return res.status(500).json({ error: 'Upload failed', message: err.message });
      }

      if (!req.file) {
        return res.status(400).json({ error: 'No file uploaded' });
      }

      const fileId = uuidv4();
      const fileData = {
        id: fileId,
        fileName: req.file.originalname,
        fileSize: req.file.size,
        filePath: req.file.path,
        peerId: req.body.peerId,
        senderId: req.body.senderId,
        status: 'completed'
      };

      try {
        this.db.saveFileTransfer(fileData);
      } catch (error) {
        console.error('Database save error:', error);
        // Clean up uploaded file
        if (fs.existsSync(req.file.path)) {
          fs.unlinkSync(req.file.path);
        }
        return res.status(500).json({ error: 'Failed to save file metadata' });
      }

      res.json({
        success: true,
        fileId: fileId,
        fileName: req.file.originalname,
        fileSize: req.file.size
      });
    });
  }

  handleDownload(req, res) {
    const fileId = req.params.fileId;

    try {
      const stmt = this.db.db.prepare('SELECT * FROM file_transfers WHERE id = ?');
      const fileRecord = stmt.get(fileId);

      if (!fileRecord) {
        return res.status(404).json({ error: 'File not found' });
      }

      const filePath = fileRecord.file_path;

      if (!fs.existsSync(filePath)) {
        return res.status(404).json({ error: 'File not found on disk' });
      }

      // Use basename to prevent path traversal
      res.download(filePath, path.basename(fileRecord.file_name), (err) => {
        if (err) {
          console.error('Download error:', err);
          if (!res.headersSent) {
            res.status(500).json({ error: 'Download failed' });
          }
        }
      });
    } catch (error) {
      console.error('Database query error:', error);
      return res.status(500).json({ error: 'Database error' });
    }
  }

  handleFileMeta(ws, message, clients) {
    const { to, from, fileName, fileSize, fileId } = message;

    // Save file transfer metadata
    this.db.saveFileTransfer({
      id: fileId,
      fileName: fileName,
      fileSize: fileSize,
      filePath: null,
      peerId: to,
      senderId: from,
      status: 'pending'
    });

    // Notify recipient about incoming file
    const recipient = clients.get(to);

    if (recipient && recipient.ws.readyState === 1) {
      recipient.ws.send(JSON.stringify({
        type: 'file-incoming',
        from: from,
        fileName: fileName,
        fileSize: fileSize,
        fileId: fileId,
        timestamp: Date.now()
      }));

      // Confirm to sender
      ws.send(JSON.stringify({
        type: 'file-meta-sent',
        to: to,
        fileId: fileId
      }));
    } else {
      ws.send(JSON.stringify({
        type: 'file-meta-failed',
        to: to,
        reason: 'Recipient offline'
      }));
    }
  }

  updateProgress(fileId, progress, speed) {
    this.db.updateFileTransferProgress(fileId, progress, speed);
  }

  completeTransfer(fileId) {
    this.db.completeFileTransfer(fileId);
  }
}

module.exports = FileTransferHandler;
